Cypher 고급 문법
가변 길이 경로, 최단 경로, 집계 함수, WITH, UNWIND 등 실전에서 자주 쓰이는 고급 패턴을 다룹니다.
기본 문법에서는 (a)-[:KNOWS]->(b)처럼 1단계 관계만 탐색했습니다.
하지만 실전에서는 "친구의 친구의 친구"처럼 여러 단계를 탐색해야 할 때가 많습니다.
// 1~3단계 KNOWS 관계 탐색 MATCH (a:Person {name: "A"})-[:KNOWS*1..3]->(friend) RETURN friend.name
*의 다양한 표기법
*1..3 → 1단계 이상, 3단계 이하
*2 → 정확히 2단계
*..5 → 최대 5단계까지 (1~5)
*3.. → 최소 3단계 이상
* → 모든 단계 (주의: 성능 이슈 가능)
성능 주의
*만 쓰면 그래프 전체를 탐색할 수 있어 매우 느려질 수 있습니다.
반드시 상한을 지정하세요: *1..5 등.
실무에서는 보통 3~5단계 이내를 사용합니다.
두 노드 사이의 가장 짧은 경로를 찾는 함수입니다.
소셜 네트워크에서 "A와 E가 몇 다리 건너 아는 사이인가?"를 알 수 있습니다.
MATCH path = shortestPath( (a:Person {name: "A"})-[*..10]->(e:Person {name: "E"}) ) RETURN path, length(path) AS 거리
MATCH path = allShortestPaths( (a:Person {name: "A"})-[*..10]->(e:Person {name: "E"}) ) RETURN path
경로(path)에서 정보 추출
length(path) → 경로의 관계 수 (거리)
nodes(path) → 경로에 포함된 노드 목록
relationships(path) → 경로에 포함된 관계 목록
shortestPath에도 상한이 필요합니다.
[*..10]처럼 최대 탐색 깊이를 지정하세요.
상한 없이 쓰면 전체 그래프를 탐색하게 됩니다.
SQL의 GROUP BY + 집계 함수와 비슷한 기능입니다.
Cypher에서는 RETURN에서 집계 함수를 쓰면 자동으로 그룹화됩니다.
// 전체 Person 수 MATCH (p:Person) RETURN count(p) AS 인원수 // 장르별 영화 수 MATCH (m:Movie) RETURN m.genre, count(m) AS 영화수 ORDER BY 영화수 DESC // 평균 평점 MATCH (:Person)-[r:WATCHED]->(:Movie) RETURN avg(r.rating) AS 평균평점
| 함수 | 설명 | 예시 |
|---|---|---|
count() |
개수 | count(n) |
sum() |
합계 | sum(r.amount) |
avg() |
평균 | avg(r.rating) |
min() / max() |
최솟값 / 최댓값 | min(n.age) |
collect() |
결과를 리스트로 모음 | collect(m.title) |
collect()는 Cypher만의 강력한 함수입니다.
여러 행의 결과를 하나의 리스트로 묶어줍니다.
MATCH (p:Person)-[:WATCHED]->(m:Movie)
RETURN p.name, collect(m.title) AS 본영화목록
결과: 홍길동 | ["인셉션", "매트릭스", "인터스텔라"]
WITH는 쿼리를 여러 단계로 나누는 파이프라인입니다.
앞 단계의 결과를 다음 단계로 전달하며, 중간에 필터링·정렬·집계를 할 수 있습니다.
MATCH (p:Person)-[:WATCHED]->(m:Movie) WITH p, count(m) AS movieCount WHERE movieCount >= 3 RETURN p.name, movieCount ORDER BY movieCount DESC
MATCH (p:Person)-[:WATCHED]->(m:Movie) WITH p, count(m) AS cnt ORDER BY cnt DESC LIMIT 5 // 상위 5명에 대해 다시 영화 목록 조회 MATCH (p)-[:WATCHED]->(m:Movie) RETURN p.name, collect(m.title) AS 영화목록
WITH의 핵심 규칙
WITH 뒤에 명시하지 않은 변수는 사라집니다.
WITH p, count(m) AS cnt → 이후 단계에서 m은 사용 불가
이것은 SQL의 서브쿼리에서 SELECT한 컬럼만 외부에서 보이는 것과 같은 원리입니다.
WITH를 쓰는 대표적 상황
1. 집계 후 필터링 — count한 뒤 WHERE로 거르기
2. 정렬 후 추가 조회 — 상위 N개를 뽑은 뒤 상세 정보 조회
3. 중간 계산 — 계산 결과를 변수에 담아 다음 단계에서 사용
UNWIND는 리스트를 개별 행으로 펼치는 명령어입니다.
collect()가 여러 행을 리스트로 모으는 것의 반대입니다.
UNWIND ["인셉션", "매트릭스", "인터스텔라"] AS title RETURN title // 결과: // "인셉션" // "매트릭스" // "인터스텔라"
UNWIND [ {name: "홍길동", age: 30}, {name: "김철수", age: 25}, {name: "이영희", age: 28} ] AS person CREATE (:Person {name: person.name, age: person.age})
collect()와 UNWIND는 짝꿍
collect(): 여러 행 → 하나의 리스트로 모으기
UNWIND: 하나의 리스트 → 여러 행으로 펼치기
데이터를 모았다가 다시 펼치는 패턴은 Cypher에서 자주 사용됩니다.
더 복잡한 조회를 위한 패턴들입니다.
// 모든 Person을 조회하되, 영화를 안 본 사람도 포함 MATCH (p:Person) OPTIONAL MATCH (p)-[:WATCHED]->(m:Movie) RETURN p.name, m.title // MATCH만 쓰면 영화를 안 본 사람은 결과에서 제외됨 // OPTIONAL MATCH는 SQL의 LEFT JOIN과 같은 역할
MATCH (p:Person) RETURN p.name, CASE WHEN p.age < 20 THEN "미성년자" WHEN p.age < 30 THEN "20대" WHEN p.age < 40 THEN "30대" ELSE "40대 이상" END AS 연령대
MATCH (m:Movie) RETURN m.title, m.year ORDER BY m.year DESC // 내림차순 정렬 SKIP 10 // 처음 10개 건너뛰기 LIMIT 5 // 5개만 반환
| 기능 | 문법 | 설명 |
|---|---|---|
| 가변 길이 경로 | [*1..3] |
1~3단계 관계 탐색 |
| 최단 경로 | shortestPath() |
두 노드 간 가장 짧은 경로 |
| 집계 | count, sum, avg, collect |
자동 그룹화 + 집계 |
| 중간 파이프 | WITH |
중간 결과를 다음 단계로 전달 |
| 리스트 펼치기 | UNWIND |
리스트를 개별 행으로 분해 |
| 선택적 매칭 | OPTIONAL MATCH |
없으면 NULL (LEFT JOIN) |
| 조건 분기 | CASE WHEN ... END |
조건부 값 반환 |
| 정렬·페이징 | ORDER BY, LIMIT, SKIP |
결과 정렬 및 범위 지정 |
기본 문법 + 고급 문법 = 실전 Cypher
기본 문법(MATCH, CREATE, SET, DELETE)으로 CRUD를 하고,
고급 문법(경로 탐색, WITH, UNWIND, 집계)으로 분석을 합니다.
이 두 페이지를 합치면 실무에서 필요한 Cypher의 90%를 커버합니다.